package cn.iocoder.yudao.module.shop.service.monthmember;

import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO;
import cn.iocoder.yudao.module.pay.service.wallet.PayWalletService;
import cn.iocoder.yudao.module.shop.dal.dataobject.dayuser.ShopDayUserDO;
import cn.iocoder.yudao.module.shop.dal.dataobject.item.ShopItemDO;
import cn.iocoder.yudao.module.shop.dal.dataobject.order.ShopOrderDO;
import cn.iocoder.yudao.module.shop.dal.dataobject.order.ShopOrderItemDO;
import cn.iocoder.yudao.module.shop.enums.store.ChargeTypeEnum;
import cn.iocoder.yudao.module.shop.service.item.ShopItemService;
import cn.iocoder.yudao.module.shop.service.order.ShopOrderItemService;
import cn.iocoder.yudao.module.shop.service.order.dto.ShopOrderItemHandleDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.bouncycastle.asn1.esf.CrlValidatedID;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import cn.iocoder.yudao.module.shop.controller.admin.monthmember.vo.*;
import cn.iocoder.yudao.module.shop.dal.dataobject.monthmember.ShopMonthMemberDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;

import cn.iocoder.yudao.module.shop.convert.monthmember.ShopMonthMemberConvert;
import cn.iocoder.yudao.module.shop.dal.mysql.monthmember.ShopMonthMemberMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.shop.enums.ErrorCodeConstants.*;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;

/**
 * 顾客每月到店统计 Service 实现类
 *
 * @author 曹建伟
 */
@Service
@Validated
public class ShopMonthMemberServiceImpl implements ShopMonthMemberService {

    @Resource
    private ShopMonthMemberMapper monthMemberMapper;

    @Resource
    private MemberUserApi memberUserApi;

    @Resource
    private PayWalletService payWalletService;

    @Resource
    private ShopOrderItemService shopOrderItemService;

    @Resource
    private ShopItemService shopItemService;

    @Override
    public Long createMonthMember(ShopMonthMemberCreateReqVO createReqVO) {
        // 插入
        ShopMonthMemberDO monthMember = ShopMonthMemberConvert.INSTANCE.convert(createReqVO);

        LocalDateTime now = LocalDateTime.now();
        monthMember.setUpdateTime(now);
        monthMember.setCreateTime(now);

        monthMemberMapper.insert(monthMember);
        // 返回
        return monthMember.getId();
    }

    @Override
    public void updateMonthMember(ShopMonthMemberUpdateReqVO updateReqVO) {
        // 校验存在
        validateMonthMemberExists(updateReqVO.getId());
        // 更新
        ShopMonthMemberDO updateObj = ShopMonthMemberConvert.INSTANCE.convert(updateReqVO);
        monthMemberMapper.updateById(updateObj);
    }

    @Override
    public void deleteMonthMember(Long id) {
        // 校验存在
        validateMonthMemberExists(id);
        // 删除
        monthMemberMapper.deleteById(id);
    }

    private void validateMonthMemberExists(Long id) {
        if (monthMemberMapper.selectById(id) == null) {
            throw exception(MONTH_MEMBER_NOT_EXISTS);
        }
    }

    @Override
    public ShopMonthMemberDO getMonthMember(Long id) {
        return monthMemberMapper.selectById(id);
    }

    @Override
    public List<ShopMonthMemberDO> getMonthMemberList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return ListUtil.empty();
        }
        return monthMemberMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<ShopMonthMemberDO> getMonthMemberPage(ShopMonthMemberPageReqVO pageReqVO) {
        return monthMemberMapper.selectPage(pageReqVO);
    }

    @Override
    public List<ShopMonthMemberDO> getMonthMemberList(ShopMonthMemberExportReqVO exportReqVO) {
        return monthMemberMapper.selectList(exportReqVO);
    }

    private ShopMonthMemberDO get(String dateId, Long memberId){
        ShopMonthMemberDO monthMemberDO = monthMemberMapper.selectOne(new LambdaQueryWrapper<ShopMonthMemberDO>()
                .eq(ShopMonthMemberDO::getDateId, dateId)
                .eq(ShopMonthMemberDO::getMemberId, memberId));

        return monthMemberDO;
    }

    private ShopMonthMemberDO getOrCreate(String dateId, Long memberId, Long tenantId){
        ShopMonthMemberDO monthMemberDO = monthMemberMapper.selectOne(new LambdaQueryWrapper<ShopMonthMemberDO>()
                .eq(ShopMonthMemberDO::getDateId, dateId)
                .eq(ShopMonthMemberDO::getMemberId, memberId));

        if(monthMemberDO == null){
            MemberUserRespDTO memberUserRespDTO = memberUserApi.getUser(memberId);
            monthMemberDO = new ShopMonthMemberDO();

            LocalDateTime now = LocalDateTime.now();
            monthMemberDO.setUpdateTime(now);
            monthMemberDO.setCreateTime(now);

            monthMemberDO.setTenantId(tenantId);

            monthMemberDO.setDateId(dateId);
            monthMemberDO.setMemberId(memberId);
            monthMemberDO.setNickname(memberUserRespDTO.getNickname());
            monthMemberDO.setAvatar(memberUserRespDTO.getAvatar());
            monthMemberDO.setMobile(memberUserRespDTO.getMobile());
            monthMemberDO.setTotalTimes(0);
            monthMemberDO.setTotalCount(0);
            monthMemberDO.setTotalPrice(0);

            monthMemberDO.setIsFirstCharge(null);
            monthMemberDO.setIsContinueCharge(null);
            monthMemberDO.setIsNoContinueCharge(null);
            monthMemberDO.setIsAfterTimesCharge(null);

            monthMemberMapper.insert(monthMemberDO);

            monthMemberDO = monthMemberMapper.selectOne(new LambdaQueryWrapper<ShopMonthMemberDO>()
                    .eq(ShopMonthMemberDO::getDateId, dateId)
                    .eq(ShopMonthMemberDO::getMemberId, memberId));

            return monthMemberDO;
        }

        return  monthMemberDO;
    }

    @Override
    public Boolean recordOrder(ShopOrderDO order, Boolean isNewMember, Long rechargeOrderCount){
        String dateId = order.getStartTime().format(DateTimeFormatter.ofPattern("yyyyMM"));
        ShopMonthMemberDO monthMemberDO = getOrCreate(dateId, order.getMemberId(), order.getTenantId());

        monthMemberDO.setCreateTime(order.getStartTime());
        monthMemberDO.setUpdateTime(order.getStartTime());

        monthMemberDO.setTotalTimes(monthMemberDO.getTotalTimes() + 1);

        ShopOrderItemHandleDTO handleDTO = shopOrderItemService.getHandleByOrderId(order.getId());

        monthMemberDO.setTotalCount(monthMemberDO.getTotalCount() + handleDTO.getHandleCount());
        monthMemberDO.setTotalPrice(monthMemberDO.getTotalPrice() + order.getPayPrice());

        if(!order.getWalletCharge()){
            if(rechargeOrderCount > 0){
                monthMemberDO.setIsNoContinueCharge(true);
            }
        }

        monthMemberMapper.updateById(monthMemberDO);

        return true;
    }

    @Override
    public Boolean rollbackOrder(ShopOrderDO order){
        String dateId = order.getStartTime().format(DateTimeFormatter.ofPattern("yyyyMM"));
        ShopMonthMemberDO monthMemberDO = getOrCreate(dateId, order.getMemberId(), order.getTenantId());

        if(monthMemberDO == null){
            return true;
        }

        monthMemberDO.setTotalTimes(monthMemberDO.getTotalTimes() - 1);

        ShopOrderItemHandleDTO handleDTO = shopOrderItemService.getHandleByOrderId(order.getId());

        monthMemberDO.setTotalCount(monthMemberDO.getTotalCount() - handleDTO.getHandleCount());
        monthMemberDO.setTotalPrice(monthMemberDO.getTotalPrice() - order.getPayPrice());

        monthMemberMapper.updateById(monthMemberDO);

        return true;
    }

    @Override
    public Boolean recordPayOrder(PayWalletRechargeDO payOrder, Long masterId, ChargeTypeEnum chargeType){
        String dateId = payOrder.getCreateTime().format(DateTimeFormatter.ofPattern("yyyyMM"));
        PayWalletDO walletDO = payWalletService.getWallet(payOrder.getWalletId());
        ShopMonthMemberDO monthMemberDO = getOrCreate(dateId, walletDO.getUserId(), payOrder.getTenantId());

        if(chargeType.getType().equals(ChargeTypeEnum.FIRST.getType())){
            monthMemberDO.setIsFirstCharge(true);
        }else if(chargeType.getType().equals(ChargeTypeEnum.CONTINUE.getType())){
            monthMemberDO.setIsContinueCharge(true);
        }else if(chargeType.getType().equals(ChargeTypeEnum.CONVERT.getType())){
            monthMemberDO.setIsAfterTimesCharge(true);
        }

        monthMemberMapper.updateById(monthMemberDO);

        return true;
    }

    @Override
    public Boolean recordTimesChargePay(Integer payPrice, Long memberId, Long masterId, ChargeTypeEnum chargeType, Long tenantId){
        String dateId = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMM"));
        ShopMonthMemberDO monthMemberDO = getOrCreate(dateId, memberId, tenantId);

        if(chargeType.getType().equals(ChargeTypeEnum.FIRST.getType())){
            monthMemberDO.setIsFirstCharge(true);
        }else if(chargeType.getType().equals(ChargeTypeEnum.CONTINUE.getType())){
            monthMemberDO.setIsContinueCharge(true);
        }else if(chargeType.getType().equals(ChargeTypeEnum.CONVERT.getType())){
            monthMemberDO.setIsAfterTimesCharge(true);
        }

        monthMemberMapper.updateById(monthMemberDO);

        return true;
    }

    @Override
    public List<ShopMonthMemberDO> getMonthMemberListByTime(LocalDateTime startTime, LocalDateTime endTime, Long tenantId){
        return monthMemberMapper.selectListByTime(startTime, endTime, tenantId);
    }

}
